package app

import (
	"IEC104_Slave/asdu"
	logger "IEC104_Slave/clog"
	"IEC104_Slave/config"
	"IEC104_Slave/cs104"
	"github.com/sirupsen/logrus"
	"math/rand"
	"strconv"
	"time"
)

func CreateNewSlave(port int) {
	host := config.Cfg.Iec.Host
	portStr := strconv.Itoa(port)

	c := cs104.DefaultConfig()
	c.SendUnAckLimitK = 100
	log := logger.InitLogger(config.Cfg.Log.Path, portStr)
	slave := cs104.NewSlave(&myslave{log, port}, host, portStr, c, log)
	slave.SetOnConnectionHandler(func(c asdu.Connect) {
		slave.Log.Infof("连接成功")
	})
	slave.SetConnectionLostHandler(func(c asdu.Connect) {
		slave.Log.Infof("连接断开")
	})
	slave.Listen()
}

type myslave struct {
	Log  *logrus.Logger
	Port int
}

// InterrogationHandler 响应总召唤/*
func (sf *myslave) InterrogationHandler(c asdu.Connect, asduPack *asdu.ASDU, qoi asdu.QualifierOfInterrogation) error {
	if slaveSession, ok := c.(*cs104.SlaveSession); ok {
		slaveSession.InGI.Store(true) // 总召唤开始
		defer func() {
			slaveSession.InGI.Store(false) // 总召唤结束时复位
			time.Sleep(2 * time.Millisecond)
			slaveSession.SendSFrame() // 主动发送S帧，同步recvNO
		}()
	}

	asduPack.SendReplyMirror(c, asdu.ActivationCon)
	var singlePointInfos []asdu.SinglePointInfo
	var measuredValueInfos []asdu.MeasuredValueFloatInfo

	for i := range 8 {
		measuredValueInfos = append(measuredValueInfos, asdu.MeasuredValueFloatInfo{
			Ioa:   asdu.InfoObjAddr(stringToUint(strconv.Itoa(i + 16385))),
			Value: rand.Float32(),
			Qds:   asdu.QDSGood,
		})
		b := rand.Int()%2 == 1
		singlePointInfos = append(singlePointInfos, asdu.SinglePointInfo{
			Ioa:   asdu.InfoObjAddr(stringToUint(strconv.Itoa(i + 1))),
			Value: b,
			Qds:   asdu.QDSGood,
		})
	}

	//currentData := config.CurrentData.Get()
	//
	//for s := range currentData {
	//	currValue := currentData[s]
	//	switch currValue.(type) {
	//	case float64:
	//		measuredValueInfos = append(measuredValueInfos, asdu.MeasuredValueFloatInfo{
	//			Ioa:   asdu.InfoObjAddr(stringToUint(s)),
	//			Value: float32(currValue.(float64)),
	//			Qds:   asdu.QDSGood,
	//		})
	//	case bool:
	//		singlePointInfos = append(singlePointInfos, asdu.SinglePointInfo{
	//			Ioa:   asdu.InfoObjAddr(stringToUint(s)),
	//			Value: currValue.(bool),
	//			Qds:   asdu.QDSGood,
	//		})
	//	}
	//}

	coa := asdu.CauseOfTransmission{
		Cause: asdu.InterrogatedByStation,
	}
	ca := asdu.GlobalCommonAddr

	if len(measuredValueInfos) != 0 {
		err := asdu.MeasuredValueFloat(c, false, coa, ca, measuredValueInfos...)
		if err != nil {
			sf.Log.Errorf("发送单点遥测数据失败: %v", err)
			return err
		}
		//sf.Log.Debugf("发送单点遥测数据成功")

	}
	if len(singlePointInfos) != 0 {
		err := asdu.Single(c, false, coa, ca, singlePointInfos...)

		if err != nil {
			sf.Log.Error("发送单点遥信数据失败: %v", err)
			return err
		}
		//sf.Log.Debugf("发送单点遥信数据成功")

	}
	// 发送激活结束
	asduPack.SendReplyMirror(c, asdu.ActivationTerm)
	return nil
}
func (sf *myslave) CounterInterrogationHandler(asdu.Connect, *asdu.ASDU, asdu.QualifierCountCall) error {
	return nil
}
func (sf *myslave) ReadHandler(asdu.Connect, *asdu.ASDU, asdu.InfoObjAddr) error { return nil }
func (sf *myslave) ClockSyncHandler(asdu.Connect, *asdu.ASDU, time.Time) error   { return nil }
func (sf *myslave) ResetProcessHandler(asdu.Connect, *asdu.ASDU, asdu.QualifierOfResetProcessCmd) error {
	return nil
}
func (sf *myslave) DelayAcquisitionHandler(asdu.Connect, *asdu.ASDU, uint16) error { return nil }
func (sf *myslave) ASDUHandler(asdu.Connect, *asdu.ASDU) error                     { return nil }

// LoopListenData  上送突发数据/*
func (sf *myslave) LoopListenData(c asdu.Connect) error {

	if slaveSession, ok := c.(*cs104.SlaveSession); ok {
		defer func() {
			time.Sleep(2 * time.Millisecond)
			slaveSession.SendSFrame() // 主动发送S帧，同步recvNO
		}()
	}

	measuredValueInfos := make([]asdu.MeasuredValueFloatInfo, 0, 64)
	singlePointInfos := make([]asdu.SinglePointInfo, 0, 64)

	for i := range 30 {
		measuredValueInfos = append(measuredValueInfos, asdu.MeasuredValueFloatInfo{
			Ioa:   asdu.InfoObjAddr(stringToUint(strconv.Itoa(i + 16385))),
			Value: rand.Float32(),
			Qds:   asdu.QDSGood,
		})
		b := rand.Int()%2 == 1
		singlePointInfos = append(singlePointInfos, asdu.SinglePointInfo{
			Ioa:   asdu.InfoObjAddr(stringToUint(strconv.Itoa(i + 1))),
			Value: b,
			Qds:   asdu.QDSGood,
		})
	}

	//1) 读取快照，确保无竞态
	//currentData := config.CurrentData.Get()
	//lastData := config.LastData.Get()
	//for k, curr := range currentData {
	//	last, exists := lastData[k]
	//	if exists && reflect.DeepEqual(last, curr) {
	//		continue
	//	}
	//	switch v := curr.(type) {
	//	case float64:
	//		measuredValueInfos = append(measuredValueInfos, asdu.MeasuredValueFloatInfo{
	//			Ioa:   asdu.InfoObjAddr(stringToUint(k)),
	//			Value: float32(v),
	//			Qds:   asdu.QDSGood,
	//		})
	//	case bool:
	//		singlePointInfos = append(singlePointInfos, asdu.SinglePointInfo{
	//			Ioa:   asdu.InfoObjAddr(stringToUint(k)),
	//			Value: v,
	//			Qds:   asdu.QDSGood,
	//		})
	//	}
	//}

	// 2) 无变化直接返回
	if len(measuredValueInfos) == 0 && len(singlePointInfos) == 0 {
		return nil
	}

	coa := asdu.CauseOfTransmission{Cause: asdu.Spontaneous}
	ca := asdu.GlobalCommonAddr

	if len(measuredValueInfos) > 0 {
		if err := asdu.MeasuredValueFloat(c, false, coa, ca, measuredValueInfos...); err != nil {
			sf.Log.Errorf("发送遥测(M_ME_NC_1)失败: %v", err)
			return err
		}
		sf.Log.Debug("发送遥测(M_ME_NC_1)成功")
	}
	if len(singlePointInfos) > 0 {
		if err := asdu.Single(c, false, coa, ca, singlePointInfos...); err != nil {
			sf.Log.Errorf("发送遥信(M_SP_NA_1)失败: %v", err)
			return err
		}
		sf.Log.Debug("发送遥信(M_SP_NA_1)成功")
	}

	return nil
}

// SingleCommandHandler 接收单点遥控/*
func (sf *myslave) SingleCommandHandler(c asdu.Connect, asduPack *asdu.ASDU, point asdu.SingleCommandInfo) error {
	sf.Log.Debugf("收到单点遥控命令: Ioa=%d, Value=%v, 传送原因=%d",
		point.Ioa, point.Value, asduPack.Identifier.Coa.Cause)
	point.Time = time.Now()
	//保存文件
	//utils.SaveJsonFileNoName(point)

	// 2. 返回确认信息（激活确认/停止激活确认）
	var replyCause asdu.CauseOfTransmission
	switch asduPack.Identifier.Coa.Cause {
	case asdu.Activation:
		replyCause = asdu.CauseOfTransmission{Cause: asdu.ActivationCon} // 激活确认
	case asdu.Deactivation:
		replyCause = asdu.CauseOfTransmission{Cause: asdu.DeactivationCon} // 停止激活确认
	default:
		return asdu.ErrCmdCause
	}

	// 3. 发送确认ASDU（镜像原命令的结构，仅修改传送原因）
	if err := asdu.SingleCmd(
		c,
		asduPack.Identifier.Type, // 保持原类型（C_SC_NA_1或C_SC_TA_1）
		replyCause,
		asduPack.CommonAddr,
		point, // 复用原命令信息
	); err != nil {
		sf.Log.Errorf("发送单点命令确认失败: %v", err)
		return err
	}

	//4. 发送激活终止
	if err := asdu.SingleCmd(
		c,
		asduPack.Identifier.Type,
		asdu.CauseOfTransmission{Cause: asdu.ActivationTerm},
		asduPack.CommonAddr,
		point,
	); err != nil {
		sf.Log.Errorf("发送单点遥控命令终止失败: %v", err)
		return err
	}
	sf.Log.Debugf("单点遥控命令处理完成: Ioa=%d", point.Ioa)
	return nil
}

// SetpointFloatCommandHandler 接收单点遥调/*
func (sf *myslave) SetpointFloatCommandHandler(c asdu.Connect, asduPack *asdu.ASDU, point asdu.SetpointCommandFloatInfo) error {
	sf.Log.Debugf("收到单点遥调命令: Ioa=%d, Value=%v, 传送原因=%d",
		point.Ioa, point.Value, asduPack.Identifier.Coa.Cause)
	//加入一个时间
	//point.Time = time.Now()
	////保存文件
	//utils.SaveJsonFileNoName(point)
	// 2. 返回确认信息（激活确认/停止激活确认）
	var replyCause asdu.CauseOfTransmission
	switch asduPack.Identifier.Coa.Cause {
	case asdu.Activation:
		replyCause = asdu.CauseOfTransmission{Cause: asdu.ActivationCon} // 激活确认
	case asdu.Deactivation:
		replyCause = asdu.CauseOfTransmission{Cause: asdu.DeactivationCon} // 停止激活确认
	default:
		return asdu.ErrCmdCause
	}

	// 3. 发送确认ASDU（镜像原命令的结构，仅修改传送原因）
	if err := asdu.SetpointCmdFloat(
		c,
		asduPack.Identifier.Type,
		replyCause,
		asduPack.CommonAddr,
		point, // 复用原命令信息
	); err != nil {
		sf.Log.Errorf("发送单点遥调命令确认失败: %v", err)
		return err
	}

	// 3. 发送激活终止ASDU（镜像原命令的结构，仅修改传送原因）
	if err := asdu.SetpointCmdFloat(
		c,
		asduPack.Identifier.Type,
		asdu.CauseOfTransmission{Cause: asdu.DeactivationCon},
		asduPack.CommonAddr,
		point, // 复用原命令信息
	); err != nil {
		sf.Log.Errorf("发送单点遥调命令确认失败: %v", err)
		return err
	}

	// 4. 发送激活终止（可选，根据协议要求）
	//terminationCause := asdu.CauseOfTransmission{Cause: asdu.ActivationTerm}
	//if err := asdu.SingleCmd(
	//	c,
	//	asduPack.Identifier.Type,
	//	terminationCause,
	//	asduPack.CommonAddr,
	//	point,
	//); err != nil {
	//	sf.Log.Errorf("发送单点命令终止失败: %v", err)
	//	return err
	//}
	sf.Log.Debugf("单点遥调命令处理完成: Ioa=%d", point.Ioa)

	return nil
}

// stringToUint /*
func stringToUint(s string) uint {
	// 先转换为 uint64
	val, err := strconv.ParseUint(s, 10, 0)
	if err != nil {
		return 0
	}
	// 再转换为 uint（根据系统位数自动适配）
	return uint(val)
}

func cloneMap(m map[string]interface{}) map[string]interface{} {
	cp := make(map[string]interface{}, len(m))
	for k, v := range m {
		cp[k] = v
	}
	return cp
}
